/*
 * @Author: Robin
 * @Date: 2021-07-06 09:12:36
 * @LastEditors: Robin
 * @LastEditTime: 2021-07-06 10:38:48
 * @Description: Redis数据迁移
 */
package main

import (
	"flag"
	"fmt"
	"log"

	"github.com/gomodule/redigo/redis"
)

var (
	sourcePool redis.Pool
	targetPool redis.Pool
)

func main() {
	// 处理启动参数
	sourceHost := flag.String("shost", "", "源地址")
	sourcePort := flag.String("sport", "6379", "源端口")
	sourceDB := flag.Int("sdb", 0, "源数据库")
	sourcePassword := flag.String("spass", "", "源密码")
	targetHost := flag.String("thost", "", "目标地址")
	targetPort := flag.String("tport", "6379", "目标端口")
	targetDB := flag.Int("tdb", 0, "目标数据库")
	targetPassword := flag.String("tpass", "", "目标密码")
	flag.Parse()
	// 初始化redis连接池
	sourcePool = redis.Pool{
		MaxIdle:   80,
		MaxActive: 12000, // max number of connections
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", *sourceHost+":"+*sourcePort, redis.DialDatabase(*sourceDB), redis.DialPassword(*sourcePassword))
			if err != nil {
				log.Fatalln(err.Error())
			}
			return c, err
		},
	}
	targetPool = redis.Pool{
		MaxIdle:   80,
		MaxActive: 12000, // max number of connections
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", *targetHost+":"+*targetPort, redis.DialDatabase(*targetDB), redis.DialPassword(*targetPassword))
			if err != nil {
				log.Fatalln(err.Error())
			}
			return c, err
		},
	}
	// 读取源数据库key，然后在目标数据库创建相同数据
	scn := sourcePool.Get()
	tcn := targetPool.Get()
	keys, err := redis.Strings(scn.Do("keys", "*"))
	if err != nil {
		log.Fatalln(err)
	}
	for _, k := range keys {
		tp, err := redis.String(scn.Do("TYPE", k))
		if err != nil {
			log.Fatalln(err)
		}
		switch tp {
		case "none":
			break
		case "string":
			val, err := redis.String(scn.Do("GET", k))
			if err != nil {
				log.Fatalln(err)
			}
			_, err = tcn.Do("SET", k, val)
			if err != nil {
				log.Fatalln(err)
			}
			fmt.Println("Transfer " + k)
			break
		case "list":
			val, err := redis.Strings(scn.Do("LRANGE", k, 0, -1))
			if err != nil {
				log.Fatalln(err)
			}
			vals := make([]interface{}, 0)
			vals = append(vals, k)
			for _, v := range val {
				vals = append(vals, v)
			}
			_, err = tcn.Do("RPUSH", vals...)
			if err != nil {
				log.Fatalln(err)
			}
			fmt.Println("Transfer " + k)
			break
		case "set":
			val, err := redis.Strings(scn.Do("SMEMBERS", k))
			if err != nil {
				log.Fatalln(err)
			}
			vals := make([]interface{}, 0)
			vals = append(vals, k)
			for _, v := range val {
				vals = append(vals, v)
			}
			_, err = tcn.Do("SADD", vals...)
			if err != nil {
				log.Fatalln(err)
			}
			fmt.Println("Transfer " + k)
			break
		case "zset":
			val, err := redis.StringMap(scn.Do("ZRANGE", k, 0, -1, "WITHSCORES"))
			if err != nil {
				log.Fatalln(err)
			}
			vals := make([]interface{}, 0)
			vals = append(vals, k)
			for k1, v := range val {
				vals = append(vals, v, k1)
			}
			_, err = tcn.Do("ZADD", vals...)
			if err != nil {
				log.Fatalln(err)
			}
			fmt.Println("Transfer " + k)
			break
		case "hash":
			val, err := redis.StringMap(scn.Do("HGETALL", k))
			if err != nil {
				log.Fatalln(err)
			}
			vals := make([]interface{}, 0)
			vals = append(vals, k)
			for k1, v := range val {
				vals = append(vals, k1, v)
			}
			_, err = tcn.Do("HMSET", vals...)
			if err != nil {
				log.Fatalln(err)
			}
			fmt.Println("Transfer " + k)
			break
		}
	}
	fmt.Println("Transfer Success")
}
